package coderead.plugin;
/**
 * @Copyright 源码阅读网 http://coderead.cn
 */

import coderead.plugin.bean.SimpleArtifactInfo;
import coderead.plugin.bean.SimpleSearchResult;
import coderead.plugin.ui.StyleText;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.treeStructure.Tree;

import javax.swing.*;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.function.IntPredicate;

import static com.intellij.ui.SimpleTextAttributes.GRAYED_BOLD_ATTRIBUTES;
import static com.intellij.ui.SimpleTextAttributes.GRAYED_SMALL_ATTRIBUTES;
import static com.intellij.ui.SimpleTextAttributes.REGULAR_ATTRIBUTES;

/**
 * @author 鲁班大叔
 * @date 2021
 */
public class ArtifactSearchHandler implements SearchPopupFrameUI.SearchHandler {
    private final SearchPopupFrameUI popupFrameUI;
    private final MyTreeCellRenderer treeCellRenderer;
    List<SimpleSearchResult> results = new ArrayList<>();
    private static final Logger LOG = Logger.getInstance(ArtifactSearchHandler.class);
    private Tree tree;
    private TreeModel treeModel;


    public ArtifactSearchHandler(SearchPopupFrameUI popupFrameUI, Tree tree) {
        this.tree = tree;
        this.popupFrameUI = popupFrameUI;
        // TODO 研究异步加载树 AsyncTreeModel(
        treeModel = new MyTreeModel();
        treeCellRenderer = new MyTreeCellRenderer();
    }

    @Override
    public void selectItem(TreePath path) {
        Object data = path.getLastPathComponent();
        if (data instanceof SimpleSearchResult) {
            SimpleSearchResult re = (SimpleSearchResult) data;
            if (re.getVersions() != null) {
                popupFrameUI.setDescribeText(re.getVersions().get(0).getDescription());
                return;
            } else {
                popupFrameUI.myAlarm.cancelAllRequests();
                popupFrameUI.setPaintBusy(true);
                popupFrameUI.myAlarm.addRequest(() -> {
                    tryLoadVersion((SimpleSearchResult) data);
                    popupFrameUI.setDescribeText(re.getVersions().get(0).getDescription());
                    popupFrameUI.setPaintBusy(false);
                }, 200);
            }
        } else if (data instanceof SimpleArtifactInfo) {
            popupFrameUI.setDescribeText(((SimpleArtifactInfo) data).getDescription());
        }
    }

    private ListPopup buildMenu(SimpleArtifactInfo info) {
        DataContext context = DataManager.getInstance().getDataContext(popupFrameUI);
        final DefaultActionGroup group = new DefaultActionGroup();
        group.add(popupFrameUI.createCopyTextAction("copy of Maven"
                , PluginContext.buildMavenText(info)
                , t -> PluginContext.count(info)));
        group.add(popupFrameUI.createCopyTextAction("copy of Kotlin"
                , PluginContext.buildGradleKotlinText(info)
                , t -> PluginContext.count(info)));
        group.add(popupFrameUI.createCopyTextAction("copy of Groovy Long"
                , PluginContext.buildGroovyLongText(info)
                , t -> PluginContext.count(info)));
        group.add(popupFrameUI.createCopyTextAction("copy of Groovy Short"
                , PluginContext.buildGroovyShortText(info)
                , t -> PluginContext.count(info)));
        return JBPopupFactory.getInstance()
                             .createActionGroupPopup("选择操作", group, context,
                                     JBPopupFactory.ActionSelectionAid.SPEEDSEARCH,
                                     true);
    }

    @Override
    public TreeModel getTreeModel() {
        return treeModel;
    }

    @Override
    public TreeCellRenderer getTreeCellRenderer() {
        return treeCellRenderer;
    }


    @Override
    public void processSearch(String text) throws IOException {

        List<SimpleSearchResult> simpleSearchResults =
                StringUtil.isEmpty(text) ? new ArrayList<>() :
                        PluginContext.searchArtifact(text);
        SwingUtilities.invokeLater(() -> {
            ArtifactSearchHandler.this.results = simpleSearchResults;
            tree.setModel(null);
            tree.setModel(getTreeModel());
            tree.updateUI();
            if (!simpleSearchResults.isEmpty()) {
                tree.setSelectionRow(0);
            } else {
                popupFrameUI.setDescribeText("");
            }
        });
    }

    @Override
    public void actionItem(TreePath path) {
        if (path == null) {
            return;
        }
        Object data = path.getLastPathComponent();
        if (data instanceof SimpleArtifactInfo) {
            // 弹出菜单
            Rectangle pathBounds = tree.getPathBounds(path);
            Point location = pathBounds.getLocation();
            location.y += tree.getRowHeight();
            RelativePoint point = new RelativePoint(tree, location);
            buildMenu((SimpleArtifactInfo) data).show(point);
        }
    }


    private void tryLoadVersion(final SimpleSearchResult artifact) {
        if (artifact.getVersions() != null) {
            return;
        }
        List<SimpleArtifactInfo> allArtifact;
        try {
            allArtifact = PluginContext.getAllArtifact(artifact.groupId, artifact.artifactId);
            artifact.setVersions(allArtifact);
        } catch (IOException e) {
            LOG.error(e);
        }
    }


    private class MyTreeModel implements TreeModel {
        @Override
        public Object getRoot() {
            return results;
        }

        @Override
        public Object getChild(Object parent, int index) {
            if (parent == results) {
                return results.get(index);
            } else if (parent instanceof SimpleSearchResult) {
                SimpleSearchResult r = (SimpleSearchResult) parent;
                tryLoadVersion(r);
                return ((SimpleSearchResult) parent).getVersions().get(index);
            }
            return null;
        }

        @Override
        public int getChildCount(Object parent) {
            if (parent == results) {
                return results.size();
            } else if (parent instanceof SimpleSearchResult) {
                tryLoadVersion((SimpleSearchResult) parent);
                return ((SimpleSearchResult) parent).getVersions().size();
            }
            return 0;
        }

        @Override
        public boolean isLeaf(Object node) {
            return node instanceof SimpleArtifactInfo;
        }

        @Override
        public void valueForPathChanged(TreePath path, Object newValue) {

        }

        @Override
        public int getIndexOfChild(Object parent, Object child) {
            if (parent == results) {
                return results.indexOf(child);
            } else if (parent instanceof SimpleSearchResult) {
                tryLoadVersion((SimpleSearchResult) parent);
                return ((SimpleSearchResult) parent).getVersions().indexOf(child);
            }
            return 0;
        }

        @Override
        public void addTreeModelListener(TreeModelListener l) {

        }

        @Override
        public void removeTreeModelListener(TreeModelListener l) {

        }
    }

    private class MyTreeCellRenderer extends ColoredTreeCellRenderer {


        @Override
        public void customizeCellRenderer(JTree tree,
                                          Object value,
                                          boolean selected,
                                          boolean expanded,
                                          boolean leaf,
                                          int row,
                                          boolean hasFocus) {
            if (value instanceof SimpleSearchResult) {
                artifactCellRenderer((SimpleSearchResult) value, this, selected);
                return;
            }

            if (value instanceof SimpleArtifactInfo) {
                SimpleArtifactInfo info = (SimpleArtifactInfo) value;
                // TODO 截断超出字符
                String versionText = info.version.substring(0, Math.min(info.version.length(), 12));
                append(versionText);
                appendTextPadding(100, SwingConstants.LEFT);
                String lastTime = new SimpleDateFormat("yyyy-MM-dd").format(new Date(info.getLastModified()));
                append(lastTime, GRAYED_SMALL_ATTRIBUTES);
                appendTextPadding(200, SwingConstants.LEFT);
                append(info.getDownloads() + "", GRAYED_SMALL_ATTRIBUTES);
            }
        }

        private void artifactCellRenderer(SimpleSearchResult value, ColoredTreeCellRenderer renderer, boolean selected) {
            // 是否匹配搜索 条件
            IntPredicate searchMatch = i -> Arrays.stream(value.getMatchIndex()).anyMatch(m -> m == i);
            // 添加主文本 ArtifactId
            char[] chars = value.getMatchText().toCharArray();
            boolean isMain = true;
            StyleText current = null;
            for (int i = 0; i < chars.length; i++) {
                String fragment = String.valueOf(chars[i]);
                if (":".equals(fragment)) {
                    renderer.append(current.text.trim(), current.style, current.isMain);
                    current = null;
                    isMain = false;
                    renderer.append("  ");
                    continue;
                }
                StyleText styleText;
                // 匹配搜索
                if (searchMatch.test(i) && selected) {
                    styleText = new StyleText(fragment, isMain ? StyleText.searchMatchMainStyle : StyleText.searchMatchSubStyle, isMain);
                } else {
                    styleText = new StyleText(fragment, isMain ? REGULAR_ATTRIBUTES : GRAYED_SMALL_ATTRIBUTES, isMain);
                }
                if (current == null) {
                    current = styleText;
                } else if (!current.merge(styleText)) {
                    renderer.append(current.text.trim(), current.style, current.isMain);
                    current = styleText;
                }
            }
            renderer.append(current.text.trim(), current.style, current.isMain);
//            renderer.setTextAlign(SwingConstants.TRAILING);
            // TODO 单位转换
            renderer.append(" " + value.hot, GRAYED_BOLD_ATTRIBUTES);
        }
    }
}
